/* sched.c
 * By: Ariq Chowdhury
 * Created: March 31, 2011
 * Modified by: Teresa Hume
 *              Samuel Ferguson
 * Modified: April 4, 2011
 */

#include <proc.h>
#include <sched.h>
#include <stddef.h>
#include <definitions.h>
#include <xxxio.h>

/* void schedule() */
/* { */
/*    struct task_struct *next;  */

/*    if(dequeue_task(&next, TASK_RUNNING) != SUCCESS){  */
/*      xprintf("sched.c: failed to scheduleline %i\n", __LINE__);  */
/*      return;  */
/*    } */

/*    xprintf("sched.c:%i ", __LINE__);  */
/*    /\* print_running_queue(); *\/ */
/*    printTask(current); */
/*    enqueue_task(current); */
/*    setCurrentTask(next); */
/*    printTask(current); */
/*    /\* setCurrentTask(current->next); *\/ */
/* } */


/* Scheduler uses round-robin algorithm */
void schedule()
{
  struct task_struct* prev_task = getCurrentTask();
  struct task_struct* next_task;
  static int call_count = 0;


  /* xprintf("sched.c:%i schedule() started. call_count = %i\n",__LINE__, */
  /* 	  call_count); */
  call_count++;
  /* xprintf("sched.c:%i prev_task->pid = %i.\n",__LINE__,prev_task->pid); */
  /* xprintf("sched.c:%i tasks[TASK_RUNNING].curr_tasks = %i.\n",__LINE__,tasks[TASK_RUNNING].curr_tasks); */

  /* if getCurrentTask returned nothing, kernel panic */
  if(NULL == prev_task) {
    xprintf("Scheduler Error: No Current Task\n");
    kernel_panic();
  }
  /* else if getCurrentTask returned the idle process and the runqueue is empty*/
  else if(0 == prev_task->pid && 0 == tasks[TASK_RUNNING].curr_tasks) {
    xprintf("KEEP RUNNING IDLE TASK\n");
    xprintf("sched.c:%i schedule() finished.\n",__LINE__);
    /* prev_task->esp0 = current_kstack; */
    setCurrentTask(prev_task); /*Keep running the idle task*/
    return;
  }
  /* if current task is idle task, but there is something on the runqueue,
   * use it. */
  else if(0 == prev_task->pid && 0 != tasks[TASK_RUNNING].curr_tasks) {
    xprintf("FIND HEAD OF RUNQUEUE\n");
    xprintf("runqueue length = %i\n", tasks[TASK_RUNNING].curr_tasks);
    xprintf("runqueue tail index = %i\n", tasks[TASK_RUNNING].tail);
    int i;
    for(i=tasks[TASK_RUNNING].head; i != tasks[TASK_RUNNING].tail;
	(i+1 == MAX_TASKS) ? i=0 : i++) {
      xprintf("runqueue-%i-pid: %i\n", i,
	      (int)tasks[TASK_RUNNING].task_queue[i].data->pid);
    }

    prev_task = tasks[TASK_RUNNING].task_queue[tasks[TASK_RUNNING].head].data;
  }


  /* xprintf("prev_task->next: %i\n", prev_task->pid); */
  /* xprintf("prev_task->next->pid: %i\n", prev_task->next->pid); */
  /* xprintf("prev_task->next->next->pid: %i\n", prev_task->next->next->pid); */


  /* TODO: Update task queues here? Check the whole running queue? */
  if(TASK_STOPPED == prev_task->state) {
    dequeue_task(&prev_task, TASK_RUNNING);
    prev_task->state = TASK_STOPPED;
    enqueue_task(prev_task);
    xprintf("TASK WAS STOPPED\n");
    /* XXX TASK_STOPPED is the queue for tasks that are completed */
  }

  /* xprintf("GOT TO THE PLACE WHERE TASK IS ACTUALLY SWITCHED\n"); */
  /*Set the current task to be the next task in the task queue */
  /*If at the end of the list, try the head of the running queue */
  /*If run queue is empty, run the idle process */
  /* dequeue_task(&next_task, TASK_RUNNING);
  enqueue_task(prev_task); */
  next_task = prev_task->next;
  if(NULL != next_task->esp0) {
    /* xprintf("sched.c:%i Setting new current task with\n", __LINE__); */
    /* xprintf("\t\tpid = %i\n", next_task->pid); */
    /* xprintf("\t\tstart_code = %i\n", next_task->mm->start_code); */
    /* xprintf("\t\tesp0 = 0x%x\n", next_task->esp0); */

    setCurrentTask(next_task);
  }
  /* XXX Not sure what this if statement does - Sam */
  /* if(NULL != prev_task->next) { */
  /*   xprintf("TRIED TO SET IT TO PREV_TASK->NEXT\n"); */
  /*   xprintf("prev_task_pid:%i\n", prev_task->pid); */
  /*   xprintf("next_task_pid:%i\n", prev_task->next->pid); */
  /*   setCurrentTask(prev_task->next); */
  /* } */
  else if(0 == tasks[TASK_RUNNING].curr_tasks)
    {
      /* setCurrentTask(tasks[TASK_RUNNING].task_queue[tasks[TASK_RUNNING].head].data);*/
      setCurrentTask(tasks[TASK_IDLE].task_queue[tasks[TASK_IDLE].head].data);
    }
  else {
    xprintf("TRIED TO SET IT TO IDLE TASK\n");
    setCurrentTask(tasks[TASK_IDLE].task_queue[tasks[TASK_IDLE].head].data);
  }
  /* xprintf("sched.c:%i schedule() finished.\n",__LINE__); */

  return;
}

